 /*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package serwer;

import Serializable.ParsedCmd;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.LinkedList;
import javax.swing.SwingWorker;

/**
 *
 * @author Marcin
 */
public class Receiver extends SwingWorker<Boolean, Void>{

    private final Socket s;
    boolean running=true;
    boolean need=false;
    int[] players = new int[]{-1,-1,-1,-1};
    UserState uS = new UserState();
    ParsedCmd toSend;
    
    public LinkedList<ParsedCmd> toSendQueue= new LinkedList<>();
    
    public Receiver(Socket s){
        this.s=s;
    }    
    
    public void end(){
        running=false;
    }
    
    public synchronized ParsedCmd sendQueue(ParsedCmd pC){
        if(pC==null){
            return toSendQueue.poll();
        }else{
            toSendQueue.push(pC);
            return null;
        }       
    }
    
    public void send(ParsedCmd msg){
        need=true;
        toSend=msg;
    }
    @Override
    protected Boolean doInBackground() throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
        ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
        NonBlockingInput<ParsedCmd> nbi = new NonBlockingInput<>(ois);
        nbi.start();
        uS.loginState=UserState.JUST_CONNECTED;
        uS.my=this;
        
        
        ParsedCmd inPC;
        ParsedCmd outPC;
        
        try{
        while(true){  
            
            if(uS.afk){ //Czy jest podejrzenie że user jest afk?
                while( uS.isTimeout() ){ //tak więc wkraczamy w pętle
                    if(nbi.ready()){ //jest odpowiedź!
                        uS.afk=false; 
                        break;
                    }
                    if(need || toSendQueue.size()!=0) break;
                }
                if(uS.afk && !need && toSendQueue.size()==0) break; //nie ma odpowiedzi, więc zrywamy połączenie
            }
            
            if(nbi.ready()){ //jest coś od klienta
                inPC=nbi.read(); //wczytujemy
                uS.lTime=System.currentTimeMillis(); //czas ostatniego odbioru
                
                Serwer.log("Klient: "+inPC.mainCmd); 
                outPC=Protocol.process(inPC,uS); //Formowanie odpowiedzi
                
                if(!outPC.isEmpty()){ //Jeśli jest odpowiedź
                    Serwer.log("Serwer: "+outPC.mainCmd);
                    oos.writeObject(outPC);
                }
                
            }
            else{ //nie ma nic od klienta
                if(need){
                    Serwer.log("Serwer: "+toSend.mainCmd);
                    oos.writeObject(toSend);
                    need=false;
                }
                ParsedCmd to=sendQueue(null);
                if(to!=null){
                    Serwer.log("Serwer: "+to.mainCmd);
                    oos.writeObject(to);
                }
                while( uS.askTime() ){ //to czekamy sobie; 
                    if(uS.IDinGame==0)
                        uS.inGame.process();
                    if(nbi.ready()) break;
                    if(need||toSendQueue.size()!=0) break;
                }
                if(nbi.isInterrupted()) break;
                if(!nbi.ready() && !need && toSendQueue.size()==0){
                    Serwer.log("Serwer: "+"UOK?");
                    oos.writeObject(new ParsedCmd("UOK?"));
                    uS.afk=true; //i oznaczamy jako afk
                    uS.afkTime=System.currentTimeMillis();
                }
            }
        }     
        }catch(Exception e){
            e.printStackTrace();
        }
        
        ois.close();
        oos.close();
        s.close();
        
        Serwer.log("He out"); //koniec ;p 
        return true;
    }
    
}